package cn.aezo.minions.utils;

import cn.aezo.utils.base.MiscU;
import cn.aezo.utils.base.ValidU;

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;

/**
 * Created by smalle on 2017/12/8.
 */
public class ClassLoaderU extends ClassLoader {
    /**
     * 是否打印编译日志
     */
    private static Boolean compileLogInfo = false;

    private static JavaCompiler javac = ToolProvider.getSystemJavaCompiler();

    /**
     * 编译，javac封装
     * @param targetPath 编译后的class文件目标路径(会基于此目录先创建包结构，再生成class)：D:/temp
     * @param sourceName java源码文件全名
     * @return 成功返回0
     */
    public static int compile(String targetPath, String sourceName) {
        if(ValidU.isEmpty(targetPath) || ValidU.isEmpty(sourceName))
            return -1;

        List<String> args = MiscU.Instance.toList("-d", targetPath, sourceName);
        if(compileLogInfo) {
            args.add("-g");
            args.add("-verbose");
        }
        String[] strings = new String[args.size()];

        return javac.run(null, null, null, args.toArray(strings));
    }

    /**
     * javac命令
     * @param args
     * @return
     */
    public static int javac(String... args) {
        // 前两个参数是输入参数、输出参数，第三个参数是编译输出信息，默认输出到System.out.err里面，从第四个参数开始，就是javac的参数
        return javac.run(null, null, null, args);
    }

    /**
     * 动态加载类（如果已存在此Class会覆盖）
     * @param classFilePath class文件路径
     * @param className 类名(包含包名)
     * @return
     */
    public static Class load(String classFilePath, String className) {
        if(ValidU.isEmpty(classFilePath) || ValidU.isEmpty(className))
            return null;

        Class clazz = null;
        try {
            File file = new File(classFilePath);

            URLClassLoader classloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
            Method add =URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
            add.setAccessible(true);
            add.invoke(classloader, new Object[]{file.toURI().toURL()});

            clazz = classloader.loadClass(className);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return clazz;
    }

    /**
     * 编译java源码并加载生成的class文件
     * @param sourceName
     * @param compileTargetPath
     * @param className
     * @return
     */
    public static Class loadClassByJavaFile(String sourceName, String compileTargetPath, String className) {
        if(ValidU.isEmpty(sourceName) || ValidU.isEmpty(compileTargetPath) || ValidU.isEmpty(className))
            return null;

        int result = compile(compileTargetPath, sourceName);
        if(result != 0)
            return null;

        String[] classNames = className.split("\\.");
        if(classNames.length == 1) {
            return load(compileTargetPath + "." + className, className);
        } else {
            compileTargetPath += compileTargetPath + "/";
            int length = classNames.length;
            for(int i = 0; i < length; i++) {
                if(i == length - 1) {
                    compileTargetPath = className.substring(0, className.length() - 1);
                    compileTargetPath += "." + classNames[i];
                } else {
                    compileTargetPath += classNames[i] + "/";
                }
            }

            return load(compileTargetPath, className);
        }
    }

    public static Boolean getCompileLogInfo() {
        return compileLogInfo;
    }

    public static void setCompileLogInfo(Boolean compileLogInfo) {
        ClassLoaderU.compileLogInfo = compileLogInfo;
    }
}
